package com.letoken.platform.app.service.impl;

import cn.wildfirechat.common.ErrorCode;
import cn.wildfirechat.pojos.Conversation;
import cn.wildfirechat.pojos.MessagePayload;
import cn.wildfirechat.pojos.SendMessageResult;
import cn.wildfirechat.sdk.MessageAdmin;
import cn.wildfirechat.sdk.model.IMResult;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.letoken.platform.app.configuration.ImDBConfig;
import com.letoken.platform.app.consumer.RedEnvelopeReturnConsumer;
import com.letoken.platform.pub.enums.LetokenApiResponseEnum;
import com.letoken.platform.pub.enums.LetokenTokenTypeEnum;
import com.letoken.platform.pub.enums.TokenTransactionStatusEnum;
import com.letoken.platform.pub.enums.TokenTransactionTypeEnum;
import com.letoken.platform.pub.exception.ApiServiceException;
import com.letoken.platform.pub.res.ApiResponse;
import com.letoken.platform.pub.util.ListUtil;
import com.letoken.platform.repo.app.dao.*;
import com.letoken.platform.repo.app.po.*;
import com.letoken.platform.repo.app.req.user.RedEnvelopeGiveReq;
import com.letoken.platform.repo.app.res.user.RedEnvelopeDetailsRes;
import com.letoken.platform.repo.utlis.GasUtils;
import com.letoken.platform.repo.utlis.PageDataUtil;
import lombok.extern.log4j.Log4j2;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

import static com.letoken.platform.pub.enums.LetokenApiResponseEnum.ERROR_APP_ASSETS_002;
import static com.letoken.platform.pub.enums.LetokenApiResponseEnum.ERROR_SHOP_RESPONSE_051;

@Log4j2
@Service
public class RedEnvelopService {

    @Resource
    private RedEnvelopeMoneysMapper redEnvelopeMoneysMapper;

    @Resource
    private RedEnvelopesMapper redEnvelopesMapper;

    @Resource
    private RedEnvelopeConfigService configService;

    @Resource
    private AppUserWalletMapper appUserWalletMapper;

    @Resource
    private GasUtils gasUtils;

    @Resource
    private AppUserMapper appUserMapper;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private RedEnvelopeConfigMapper redEnvelopeConfigMapper;

    private final static String DEFAULT_DESC = "恭喜发财，大吉大利";

    public final static BigDecimal minimumAmount = new BigDecimal("0.0001");

//    public final static BigDecimal redEnvelopGiveMinimum = new BigDecimal("0.01");


    @Resource
    private PlatformTransactionManager transactionManager;

    public ApiResponse<?> give(AppUser user, RedEnvelopeGiveReq req) {
        if (null == req.getAmount() || req.getAmount().compareTo(BigDecimal.ZERO) <= 0 || req.getAmount().stripTrailingZeros().scale() > 2 || null == req.getNumber() || req.getNumber() <= 0) {
            return ApiResponse.error(LetokenApiResponseEnum.ERROR_MALL_SMS_025);
        }

        if (2 == req.getType()) {
            if (req.getAmount().compareTo(BigDecimal.valueOf(req.getNumber()).multiply(minimumAmount)) < 0) {
                return ApiResponse.error(LetokenApiResponseEnum.ERROR_SHOP_RESPONSE_053);
            }
            try {
//                IMResult<PojoGroupInfo> resultGetGroupInfo = GroupAdmin.getGroupInfo(String.valueOf(req.getTarget()));
//                if (resultGetGroupInfo != null && resultGetGroupInfo.getErrorCode() == ErrorCode.ERROR_CODE_SUCCESS) {
//                    if (req.getNumber() > resultGetGroupInfo.getResult().getMax_member_count()) {
//                        return ApiResponse.create(ERROR_SHOP_RESPONSE_051);
//                    }
//                } else {
//                    return ApiResponse.create(ERROR_APP_ASSETS_002);
//                }
                if (req.getNumber() > getNumberOfGroupMembers(req.getTarget())) {
                    return ApiResponse.error(ERROR_SHOP_RESPONSE_051);
                }
            } catch (Exception e) {
                log.error("error to request im server;", e);
                return ApiResponse.error(ERROR_APP_ASSETS_002);
            }
        }

        Integer userId = user.getId();

        RedEnvelopeConfig redEnvelopeConfig = configService.get(req.getType());
        LocalDate today = LocalDate.now();
        TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());

        Integer redEnvelopeId;

        try {
            AppUserWallet usdtWallet = appUserWalletMapper.selectForUpdate2(userId, LetokenTokenTypeEnum.LET.getId());
            Statistical redEnvelopeStatistical = redEnvelopesMapper.countAndSumByUserIdAndTypeAndCreatedAt(userId, req.getType(), LocalDateTime.of(today, LocalTime.MIN), LocalDateTime.of(today, LocalTime.MAX));

            if (req.getAmount().compareTo(redEnvelopeConfig.getMaximumTimesPerDay()) > 0) {
                transactionManager.commit(transactionStatus);
                return ApiResponse.error(LetokenApiResponseEnum.ERROR_SHOP_RESPONSE_055);
            }

            if (redEnvelopeStatistical.getSum().add(req.getAmount()).compareTo(redEnvelopeConfig.getMaximumDailyAmount()) >= 0) {
                transactionManager.commit(transactionStatus);
                return ApiResponse.error(LetokenApiResponseEnum.ERROR_SHOP_RESPONSE_048);
            }
            BigDecimal gasFee = gasUtils.getFee(BigDecimal.ZERO, 1);
            gasUtils.systemGasFee(userId, gasFee);

            if (usdtWallet.getAvailableBalance().compareTo(req.getAmount()) < 0) {
                transactionManager.commit(transactionStatus);
                return ApiResponse.error(LetokenApiResponseEnum.ERROR_MALL_SMS_052);
            }

            AppUserWallet appUserWalletUpdate = new AppUserWallet();
            appUserWalletUpdate.setId(usdtWallet.getId());
            appUserWalletUpdate.setAvailableBalance(usdtWallet.getAvailableBalance().subtract(req.getAmount()));
            appUserWalletUpdate.updateById();

            AppUserAssetsHistory assetHistory = new AppUserAssetsHistory();
            assetHistory.setUserId(userId);
            assetHistory.setType(TokenTransactionTypeEnum.RED_ENVELOPE_SEND.getValue());
            assetHistory.setStatus(TokenTransactionStatusEnum.COMPLETED.getValue());
            assetHistory.setTokenId(LetokenTokenTypeEnum.LET.getId());
            assetHistory.setAmount(req.getAmount().negate());
            assetHistory.setBalance(appUserWalletUpdate.getAvailableBalance());
            assetHistory.setCreateTime(LocalDateTime.now());
            assetHistory.insert();

            RedEnvelope redEnvelope = new RedEnvelope();
            redEnvelope.setMoney(req.getAmount());
            redEnvelope.setDesc(StringUtils.hasLength(req.getDesc()) ? req.getDesc() : DEFAULT_DESC);
            redEnvelope.setOwner(userId);
            redEnvelope.setType(req.getType());
            redEnvelope.setTarget(req.getTarget());
            redEnvelope.setNumber(req.getNumber());
            redEnvelope.setCreatedAt(LocalDateTime.now());
            redEnvelopesMapper.insert(redEnvelope);

            redEnvelopeId = redEnvelope.getId();

            if (1 == req.getType()) {
                RedEnvelopeMoney redEnvelopeMoney = new RedEnvelopeMoney();
                redEnvelopeMoney.setRedEnvelopeId(redEnvelope.getId());
                redEnvelopeMoney.setMoney(req.getAmount());
                redEnvelopeMoney.setOwner(userId);
                redEnvelopeMoney.setMaximum(false);
                redEnvelopeMoney.insert();
            } else {
                double totalAmount = req.getAmount().doubleValue(); // 总金额
                int totalCount = req.getNumber(); // 红包数量
                double minAmount = 0.0001; // 最小红包金额

                List<RedEnvelopeMoney> redEnvelopeMoneys = new ArrayList<>(req.getNumber());
                if (totalAmount / minAmount == totalCount) {
                    for (int i = 0; i < totalCount; i++) {
                        RedEnvelopeMoney redEnvelopeMoney = new RedEnvelopeMoney();
                        redEnvelopeMoney.setRedEnvelopeId(redEnvelope.getId());
                        redEnvelopeMoney.setMoney(minimumAmount);
                        redEnvelopeMoney.setMaximum(false);
                        redEnvelopeMoney.setOwner(userId);
                        redEnvelopeMoneys.add(redEnvelopeMoney);
                    }
                } else {

                    createRedPackets6(redEnvelopeMoneys, req.getAmount().multiply(new BigDecimal(10000)).intValue(), req.getNumber(), redEnvelopeId, userId);

//                    Random random = new Random();

//                    double safeTotal = totalAmount;
//                    double maximum = 0;
//                    int indexOfMaximum = 0;
//                    for (int i = 0; i < totalCount - 1; i++) {
//                        double max = safeTotal - (totalCount - i) * minAmount;
//                        double amount = random.nextDouble() * max + minAmount;
//                        if (maximum < amount) {
//                            maximum = amount;
//                            indexOfMaximum = i;
//                        }
//                        RedEnvelopeMoney redEnvelopeMoney = new RedEnvelopeMoney();
//                        redEnvelopeMoney.setRedEnvelopeId(redEnvelope.getId());
//                        redEnvelopeMoney.setMoney(BigDecimal.valueOf(amount));
//                        redEnvelopeMoney.setOwner(userId);
//                        redEnvelopeMoney.setMaximum(false);
//                        redEnvelopeMoneys.add(redEnvelopeMoney);
//                        safeTotal -= amount;
//                    }
//                    RedEnvelopeMoney redEnvelopeMoney = new RedEnvelopeMoney();
//                    redEnvelopeMoney.setRedEnvelopeId(redEnvelope.getId());
//                    redEnvelopeMoney.setMoney(BigDecimal.valueOf(safeTotal));
//                    redEnvelopeMoney.setOwner(userId);
//                    if (maximum < safeTotal) {
//                        redEnvelopeMoney.setMaximum(true);
//                    } else {
//                        redEnvelopeMoney.setMaximum(false);
//                        redEnvelopeMoneys.get(indexOfMaximum).setMaximum(true);
//                    }
//                    redEnvelopeMoneys.add(redEnvelopeMoney);
                }
                if (req.getNumber() > 500) {
                    int currentPage = 1;
                    int pageSize = 500;
                    while (currentPage <= ListUtil.getTotalPages(redEnvelopeMoneys.size(), pageSize)) {
                        redEnvelopeMoneysMapper.batchInsert(ListUtil.getCurrentPageData(redEnvelopeMoneys, currentPage, pageSize));
                        currentPage++;
                    }
                } else {
                    redEnvelopeMoneysMapper.batchInsert(redEnvelopeMoneys);
                }
            }

            Map<String, String> messageContent = new HashMap<>();
            messageContent.put("id", String.valueOf(redEnvelopeId));
            messageContent.put("avatar", user.getHeadPortrait());
            messageContent.put("desc", req.getDesc());
            messageContent.put("nickname", user.getUserName());
            messageContent.put("redEnvelopeType", String.valueOf(req.getType()));
            boolean common = req.getType() == 1;

            sendGiveMessage(common ? 0 : 1, "U" + userId, JSON.toJSONString(messageContent), common ? "U" + req.getTarget() : req.getTarget());

            transactionManager.commit(transactionStatus);
        } catch (ApiServiceException apiServiceException) {
            transactionManager.rollback(transactionStatus);
            throw apiServiceException;
        } catch (Exception e) {
            transactionManager.rollback(transactionStatus);
            log.error("error to give red envelope;", e);
            return ApiResponse.error(ERROR_APP_ASSETS_002);
        }

        rabbitTemplate.convertAndSend(RedEnvelopeReturnConsumer.exchange, RedEnvelopeReturnConsumer.routingKey, redEnvelopeId, message -> {
            MessageProperties properties = message.getMessageProperties();
            properties.setHeader("x-delay", 86390000);
            return new Message(message.getBody(), properties);
        });
        return ApiResponse.create();
    }


    public ApiResponse<?> receive(AppUser user, Integer id, Integer pageNum, Integer size) {


        Integer userId = user.getId();
        boolean self;
        boolean common;
        RedEnvelope redEnvelope;
        RedEnvelopeMoney redEnvelopeMoneyReceived;
        Integer status;
        TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());

        try {
            Thread.sleep(400);

            redEnvelope = redEnvelopesMapper.selectForUpdate(id);
            if (null == redEnvelope || (status = redEnvelope.getStatus()) == 2) {
                transactionManager.commit(transactionStatus);
                return ApiResponse.error(LetokenApiResponseEnum.ERROR_SHOP_RESPONSE_049);
            }
            self = redEnvelope.getOwner().equals(userId);
            if ((common = (1 == redEnvelope.getType())) && self) {
                transactionManager.commit(transactionStatus);
                return ApiResponse.error(LetokenApiResponseEnum.ERROR_SHOP_RESPONSE_052);
            }
            if (redEnvelope.getStatus() == 3 || ChronoUnit.HOURS.between(LocalDateTime.now(), redEnvelope.getCreatedAt()) > 24) {
                transactionManager.commit(transactionStatus);
                return ApiResponse.error(LetokenApiResponseEnum.ERROR_SHOP_RESPONSE_050);
            }
            redEnvelopeMoneyReceived = redEnvelopeMoneysMapper.selectSelf(redEnvelope.getId(), userId);
            if (null == redEnvelopeMoneyReceived) {
                redEnvelopeMoneyReceived = redEnvelopeMoneysMapper.selectAvailable(redEnvelope.getId());
                if (null == redEnvelopeMoneyReceived) {
                    updateStatus(redEnvelope.getId(), status = 2);
                } else {
                    RedEnvelopeMoney redEnvelopeMoneyUpdate = new RedEnvelopeMoney();
                    redEnvelopeMoneyUpdate.setUserId(userId);
                    redEnvelopeMoneyUpdate.setUpdatedAt(LocalDateTime.now());
                    redEnvelopeMoneyUpdate.setId(redEnvelopeMoneyReceived.getId());
                    redEnvelopeMoneyUpdate.updateById();

                    AppUserWallet appUserWallet = appUserWalletMapper.selectForUpdate2(userId, LetokenTokenTypeEnum.LET.getId());
                    AppUserWallet appUserWalletUpdate = new AppUserWallet();
                    appUserWalletUpdate.setAvailableBalance(appUserWallet.getAvailableBalance().add(redEnvelopeMoneyReceived.getMoney()));
                    appUserWalletUpdate.setId(appUserWallet.getId());
                    appUserWalletMapper.updateById(appUserWalletUpdate);

                    AppUserAssetsHistory assetHistory = new AppUserAssetsHistory();
                    assetHistory.setUserId(userId);
                    assetHistory.setType(TokenTransactionTypeEnum.RED_ENVELOPE_RECEIVE.getValue());
                    assetHistory.setStatus(TokenTransactionStatusEnum.COMPLETED.getValue());
                    assetHistory.setTokenId(LetokenTokenTypeEnum.LET.getId());
                    assetHistory.setAmount(redEnvelopeMoneyReceived.getMoney());
                    assetHistory.setBalance(appUserWalletUpdate.getAvailableBalance());
                    assetHistory.setCreateTime(LocalDateTime.now());
                    assetHistory.insert();

                    RedEnvelopeMoney availableRedEnvelopeMoney = redEnvelopeMoneysMapper.selectAvailable(redEnvelope.getId());
                    if (null == availableRedEnvelopeMoney) {
                        updateStatus(redEnvelope.getId(), status = 2);
                    }
                }
            }
            transactionManager.commit(transactionStatus);
        } catch (Exception e) {
            transactionManager.rollback(transactionStatus);
            log.error("error to receive red envelope;", e);
            return ApiResponse.error(ERROR_APP_ASSETS_002);
        }

        AppUser redEnvelopeOwner = appUserMapper.selectSimpleUser(redEnvelope.getOwner());

        if (self) {
            sendReceiveMessage(1, "U" + userId, redEnvelopeOwner.getUserName(), redEnvelope.getTarget(), redEnvelopeOwner.getUserName(), "U" + userId);
        } else {
            if (common) {
                sendReceiveMessage(0, "U" + userId, user.getUserName(), "U" + redEnvelope.getOwner(), redEnvelopeOwner.getUserName(), null);
            } else {
                sendReceiveMessage(1, "U" + userId, user.getUserName(), redEnvelope.getTarget(), redEnvelopeOwner.getUserName(), "U" + redEnvelope.getOwner());
            }
        }

        RedEnvelopeDetailsRes redEnvelopeSnatchRes = new RedEnvelopeDetailsRes();
        Page<RedEnvelopeMoneyPage> page = redEnvelopeMoneysMapper.pageAlreadyReceived(new Page<>(pageNum, size), id);

        BigDecimal moneyOfAlreadyReceived = BigDecimal.ZERO;
        if (null != page && !CollectionUtils.isEmpty(page.getRecords())) {
            for (RedEnvelopeMoneyPage record : page.getRecords()) {
                if (record.getMaximum() && redEnvelope.getNumber() != page.getRecords().size()) {
                    record.setMaximum(false);
                }
                moneyOfAlreadyReceived = moneyOfAlreadyReceived.add(new BigDecimal(record.getMoney()));
            }
        }

        redEnvelopeSnatchRes.setOwnerNickname(redEnvelopeOwner.getUserName());
        redEnvelopeSnatchRes.setOwnerAvatar(redEnvelopeOwner.getHeadPortrait());
        redEnvelopeSnatchRes.setMoneyOfAlreadyReceived(String.valueOf(moneyOfAlreadyReceived));
        redEnvelopeSnatchRes.setNumberOfAlreadyReceived(null == page ? 0 : page.getRecords().size());
        redEnvelopeSnatchRes.setReceiveMoney(null == redEnvelopeMoneyReceived ? BigDecimal.ZERO.toString() : redEnvelopeMoneyReceived.getMoney().toString());
        redEnvelopeSnatchRes.setStatus(status);
        redEnvelopeSnatchRes.setDesc(redEnvelope.getDesc());
        redEnvelopeSnatchRes.setMoney(redEnvelope.getMoney().toString());
        redEnvelopeSnatchRes.setNumber(redEnvelope.getNumber());
        redEnvelopeSnatchRes.setId(redEnvelope.getId());
        redEnvelopeSnatchRes.setReceivePage(PageDataUtil.getPageData(page));
        redEnvelopeSnatchRes.setReceived(null != redEnvelopeMoneyReceived);
        redEnvelopeSnatchRes.setExpirationTime(redEnvelope.getCreatedAt().plusHours(24));
        redEnvelopeSnatchRes.setType(redEnvelope.getType());
        redEnvelopeSnatchRes.setOwner(redEnvelope.getOwner());
        return ApiResponse.create(redEnvelopeSnatchRes);
    }

    public ApiResponse<?> givenPage(Integer userId, Integer year, Integer pageNum, Integer size) {
        Statistical redEnvelopeStatistical = redEnvelopesMapper.countAndSumByUserId(userId);
        LocalDate firstDayOfYear = LocalDate.ofYearDay(year, 1);
        LocalDate lastDayOfYear = LocalDate.ofYearDay(year, 1).withDayOfYear(365).with(TemporalAdjusters.lastDayOfYear());
        Page<RedEnvelopePage> page = redEnvelopesMapper.page(new Page<>(pageNum, size), userId, LocalDateTime.of(firstDayOfYear, LocalTime.MIN), LocalDateTime.of(lastDayOfYear, LocalTime.MAX));
        return ApiResponse.create(PageDataUtil.getPageData(page, redEnvelopeStatistical));
    }

    public ApiResponse<?> receivedPage(Integer userId, Integer year, Integer pageNum, Integer size) {
        Statistical redEnvelopeMoneysStatistical = redEnvelopeMoneysMapper.countAndSumByUserId(userId);
        LocalDate firstDayOfYear = LocalDate.ofYearDay(year, 1);
        LocalDate lastDayOfYear = LocalDate.ofYearDay(year, 1).withDayOfYear(365).with(TemporalAdjusters.lastDayOfYear());
        Page<RedEnvelopeMoneyPage> page = redEnvelopeMoneysMapper.page(new Page<>(pageNum, size), userId, LocalDateTime.of(firstDayOfYear, LocalTime.MIN), LocalDateTime.of(lastDayOfYear, LocalTime.MAX));
        return ApiResponse.create(PageDataUtil.getPageData(page, redEnvelopeMoneysStatistical));
    }

    public ApiResponse<?> details(Integer userId, Integer id, Integer pageNum, Integer size) {

        RedEnvelope redEnvelope = redEnvelopesMapper.selectById(id);
        if (null == redEnvelope) {
            return ApiResponse.create(LetokenApiResponseEnum.ERROR_007);
        }

        RedEnvelopeDetailsRes detailsRes = new RedEnvelopeDetailsRes();
        Page<RedEnvelopeMoneyPage> page = redEnvelopeMoneysMapper.pageAlreadyReceived(new Page<>(pageNum, size), id);

        BigDecimal moneyOfAlreadyReceived = BigDecimal.ZERO;
        if (null != page && !CollectionUtils.isEmpty(page.getRecords())) {
            for (RedEnvelopeMoneyPage record : page.getRecords()) {
                if (record.getMaximum() && redEnvelope.getNumber() != page.getRecords().size()) {
                    record.setMaximum(false);
                }
                moneyOfAlreadyReceived = moneyOfAlreadyReceived.add(new BigDecimal(record.getMoney()));
            }
        }

        RedEnvelopeMoney redEnvelopeMoney = redEnvelopeMoneysMapper.selectSelf(redEnvelope.getId(), userId);

        AppUser appUser = appUserMapper.selectSimpleUser(redEnvelope.getOwner());
        detailsRes.setOwnerNickname(appUser.getUserName());
        detailsRes.setOwnerAvatar(appUser.getHeadPortrait());
        detailsRes.setNumberOfAlreadyReceived(null == page ? 0 : page.getRecords().size());
        detailsRes.setMoneyOfAlreadyReceived(String.valueOf(moneyOfAlreadyReceived));
        detailsRes.setMoney(redEnvelope.getMoney().toString());
        detailsRes.setNumber(redEnvelope.getNumber());
        detailsRes.setDesc(redEnvelope.getDesc());
        detailsRes.setReceivePage(PageDataUtil.getPageData(page));
        detailsRes.setStatus(redEnvelope.getStatus());
        detailsRes.setReceived(null != redEnvelopeMoney);
        detailsRes.setReceiveMoney(null == redEnvelopeMoney ? BigDecimal.ZERO.toString() : redEnvelopeMoney.getMoney().toString());
        detailsRes.setId(id);
        detailsRes.setType(redEnvelope.getType());
        detailsRes.setExpirationTime(redEnvelope.getCreatedAt().plusHours(24));
        detailsRes.setOwner(redEnvelope.getOwner());
        return ApiResponse.create(detailsRes);
    }

    public void updateStatus(Integer id, Integer status) {
        RedEnvelope redEnvelopeUpdate = new RedEnvelope();
        redEnvelopeUpdate.setStatus(status);
        redEnvelopeUpdate.setId(id);
        redEnvelopeUpdate.updateById();
    }

    public void sendGiveMessage(int convType, String sender, String content, String target) throws Exception {
        Conversation conversation = new Conversation();
        conversation.setTarget(target);
        conversation.setType(convType);
        MessagePayload messagePayload = new MessagePayload();
        messagePayload.setType(10001);
        messagePayload.setSearchableContent(content);
        IMResult<SendMessageResult> messageResultIMResult = MessageAdmin.sendMessage(sender, conversation, messagePayload);

        if (!ErrorCode.ERROR_CODE_SUCCESS.equals(messageResultIMResult.getErrorCode()) || null == messageResultIMResult.getResult()) {
            log.error("send red envelope message error;");
            throw new Exception("send red envelope message error;");
        }
    }

    public void sendReceiveMessage(int convType, String sender, String senderName, String receiver, String receiverName, String designatedUser) {
        try {
            Conversation conversation = new Conversation();
            conversation.setTarget(receiver);
            conversation.setType(convType);
            MessagePayload messagePayload = new MessagePayload();
            messagePayload.setType(10002);

            HashMap<String, String> params = new HashMap<>();
            params.put("senderName", senderName);
            params.put("receiverName", receiverName);
            if (null == designatedUser) {
                params.put("sender", sender);
                params.put("receiver", receiver);
                messagePayload.setExtra(JSON.toJSONString(params));
                MessageAdmin.sendMessage(sender, conversation, messagePayload);
            } else {
                params.put("sender", sender);
                params.put("receiver", designatedUser);
                messagePayload.setExtra(JSON.toJSONString(params));
                MessageAdmin.sendMessage(sender, conversation, messagePayload, Collections.singletonList(designatedUser));
            }
        } catch (Exception e) {
            log.error("error to send message;", e);
        }
    }

    public ApiResponse<?> configs() {
        return ApiResponse.create(redEnvelopeConfigMapper.list().stream().map(this::cover).collect(Collectors.toList()));
    }

    public Integer getNumberOfGroupMembers(String groupId) throws SQLException {

        String sql = "select _member_count from t_group where _gid = ?";

        try (Connection connection = ImDBConfig.imDataSource.getConnection(); PreparedStatement ps = connection.prepareStatement(sql)) {
            ps.setString(1, groupId);
            try (ResultSet rs = ps.executeQuery()) {
                rs.next();
                return rs.getInt(1);
            }
        }
    }

    public RedEnvelopeConfigVo cover(RedEnvelopeConfig redEnvelopeConfig) {
        return new RedEnvelopeConfigVo(redEnvelopeConfig.getType(), redEnvelopeConfig.getMaximumTimesPerDay().toString(), redEnvelopeConfig.getMaximumDailyAmount().toString());
    }


    public void createRedPackets6(List<RedEnvelopeMoney> redEnvelopeMoneys, int totalAmount, int number, int redEnvelopeId, int userId) {


        Random random = new Random();

        int remainingAmount = totalAmount;
        int remainingNumber = number;

        int indexOfMaximum = 0;
        int maximum = 0;

        boolean unevenAmount = random.nextBoolean() && random.nextBoolean() && random.nextBoolean() && random.nextBoolean();
        BigDecimal divisor = new BigDecimal(10000);
        for (int i = 0; i < number - 1; i++) {
            int max;
            if (unevenAmount) {
                max = remainingAmount / (remainingNumber * 2);
            } else {
                max = remainingAmount / remainingNumber * 2;
            }
            int amount = (int) (random.nextDouble() * (double) max);
            amount = Math.max(amount, 1);

            if (amount > maximum) {
                maximum = amount;
                indexOfMaximum = i;
            }

            RedEnvelopeMoney redEnvelopeMoney = new RedEnvelopeMoney();
            redEnvelopeMoney.setRedEnvelopeId(redEnvelopeId);
            redEnvelopeMoney.setMoney(new BigDecimal(amount).divide(divisor));
            redEnvelopeMoney.setMaximum(false);
            redEnvelopeMoney.setOwner(userId);
            redEnvelopeMoneys.add(redEnvelopeMoney);

            remainingAmount -= amount;
            remainingNumber--;
        }

        if (maximum < remainingAmount) {
            indexOfMaximum = number - 1;
        }

        RedEnvelopeMoney redEnvelopeMoney = new RedEnvelopeMoney();
        redEnvelopeMoney.setRedEnvelopeId(redEnvelopeId);
        redEnvelopeMoney.setMoney(new BigDecimal(remainingAmount).divide(divisor));
        redEnvelopeMoney.setMaximum(false);
        redEnvelopeMoney.setOwner(userId);
        redEnvelopeMoneys.add(redEnvelopeMoney);
        redEnvelopeMoneys.get(indexOfMaximum).setMaximum(true);
    }

    public static void main(String[] args) {

//        List<RedEnvelopeMoney> redPackets = new RedEnvelopService().createRedPackets6(5000000, 30, 1, 1);
////        List<Integer> redPackets = createRedPackets2(3, 10);
//
//        BigDecimal sum = BigDecimal.ZERO;
//
//        for (RedEnvelopeMoney redPacket : redPackets) {
//
//
//            System.out.println("红包金额：" + redPacket.getMoney() + "  是否是最大：" + redPacket);
//
//            sum = sum.add(redPacket.getMoney());
//        }
//
//        System.out.println("总红包金额：" + sum);
    }
}